package com.frank.oj.service.admin.account.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.frank.model.entity.user.UserInfo;
import com.frank.model.entity.user.UserRecord;
import com.frank.model.entity.user.UserRole;
import com.frank.oj.common.exception.StatusFailException;
import com.frank.oj.common.result.CommonResult;
import com.frank.oj.constant.Constants;
import com.frank.oj.manager.AdminNoticeManager;
import com.frank.oj.model.dto.AdminEditUserDTO;
import com.frank.oj.model.vo.UserRolesVO;
import com.frank.oj.service.admin.account.UserService;
import com.frank.oj.service.entity.user.UserInfoEntityService;
import com.frank.oj.service.entity.user.UserRecordEntityService;
import com.frank.oj.service.entity.user.UserRoleEntityService;
import com.frank.oj.shiro.AccountProfile;
import com.frank.oj.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author frank
 * @Date 2024/3/27
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Resource
    private UserRoleEntityService userRoleEntityService;
    @Resource
    private UserInfoEntityService userInfoEntityService;
    @Resource
    private AdminNoticeManager adminNoticeManager;

    @Resource
    private UserRecordEntityService userRecordEntityService;
    @Resource
    private RedisUtils redisUtils;
    @Override
    public IPage<UserRolesVO> getUserList(Integer limit, Integer currentPage, Boolean onlyAdmin, String keyword) {
        if (currentPage==null||currentPage<1) currentPage=1;
        if (limit==null||limit<1) limit=10;
        if (keyword!=null){
            keyword=keyword.trim();
        }
        return userRoleEntityService.getUserList(limit,currentPage,keyword,onlyAdmin);
    }

    @Override
    public void editUser(AdminEditUserDTO adminEditUserDTO) throws StatusFailException {
        String username = adminEditUserDTO.getUsername();
        String uid = adminEditUserDTO.getUid();
        String realname = adminEditUserDTO.getRealname();
        String email = adminEditUserDTO.getEmail();
        String password = adminEditUserDTO.getPassword();
        Integer type = adminEditUserDTO.getType();
        Integer status = adminEditUserDTO.getStatus();
        Boolean setNewPwd = adminEditUserDTO.getSetNewPwd();
        String titleName = adminEditUserDTO.getTitleName();
        String titleColor = adminEditUserDTO.getTitleColor();

        if (!StringUtils.isEmpty(realname) && realname.length() > 50) {
            throw new StatusFailException("真实姓名的长度不能超过50位");
        }

        if (!StringUtils.isEmpty(titleName) && titleName.length() > 20) {
            throw new StatusFailException("头衔的长度建议不要超过20位");
        }

        if (!StringUtils.isEmpty(password) && (password.length() < 6 || password.length() > 20)) {
            throw new StatusFailException("密码长度建议为6~20位！");
        }

        if (username.length() > 20) {
            throw new StatusFailException("用户名长度建议不能超过20位!");
        }

        if (StrUtil.isBlank(email)){
            email=null;
        }else {
            LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(UserInfo::getUuid,UserInfo::getEmail).eq(UserInfo::getEmail,email);
            UserInfo userInfo = userInfoEntityService.getOne(queryWrapper);

            if (userInfo!=null&&!Objects.equals(userInfo.getUuid(),adminEditUserDTO.getUid())){
                throw new StatusFailException("当前邮箱📫已绑定账号，请用其他邮箱重试");
            }
        }

        LambdaUpdateWrapper<UserInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserInfo::getUuid,uid)
                .set(UserInfo::getUsername,username)
                .set(UserInfo::getRealname,realname)
                .set(UserInfo::getEmail,email)
                .set(setNewPwd,UserInfo::getPassword, SecureUtil.md5(password))
                .set(UserInfo::getTitleName,titleName)
                .set(UserInfo::getTitleColor,titleColor)
                .set(UserInfo::getStatus,status);
        boolean update = userInfoEntityService.update(updateWrapper);

        LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserRole::getUid,uid);
        UserRole userRole = userRoleEntityService.getOne(queryWrapper,false);

        boolean changeUserRole=false;
        int oldType = userRole.getRoleId().intValue();

        if (oldType!=type){
            userRole.setRoleId((long)type);
            changeUserRole=userRoleEntityService.updateById(userRole);
            if (type==1000||oldType==1000){
                String key= Constants.Account.SUPER_ADMIN_UID_LIST_CACHE.getCode();
                redisUtils.del(key);
            }
        }
        if (update&&setNewPwd){
            userRoleEntityService.deleteCache(uid,true);
        }else if (changeUserRole){
            userRoleEntityService.deleteCache(uid,false);
        }

        if (changeUserRole){
            AccountProfile userRoleVO = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
            String title = "权限变更通知(Authority Change Notice)";
            String content = userRoleEntityService.getAuthChangeContent(oldType, type);
            adminNoticeManager.addSingleNoticeToUSer(userRoleVO.getUid(),uid,title,content,"Sys");
        }
    }

    @Override
    public void deleteUser(Map<String, Object> params) throws StatusFailException {
        List<String> deleteIds = new ArrayList<>();
        deleteIds=(List<String>)params.get("ids");

        boolean isOk = userInfoEntityService.removeByIds(deleteIds);
        if (!isOk){
            throw new StatusFailException("删除失败");
        }

        AccountProfile userRole = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
        log.info("[{}],[{}],uidList:[{}],operatorUid:[{}],operatorUsername:[{}]",
                "Admin_User", "Delete", deleteIds, userRole.getUid(), userRole.getUsername());
    }

    @Override
    public void insertBatchUser(List<List<String>> users) throws StatusFailException {
        List<String> successUidList = new LinkedList<>();
        if (users!=null){
            Set<String> failedUserNameSet = new HashSet<>();

            for (List<String> user : users) {
                try {
                    String uuid=addNewUser(user);
                    if (uuid!=null){
                        successUidList.add(uuid);
                    }else{
                        failedUserNameSet.add(user.get(0));
                    }
                }catch (Exception e){
                    failedUserNameSet.add(user.get(0));
                }
            }

            if (!successUidList.isEmpty()){
                adminNoticeManager.syncNoticeToNewRegisterBatchUser(successUidList);
            }
            if (!failedUserNameSet.isEmpty()){
                int failedCount = failedUserNameSet.size();
                int successCount = users.size() - failedCount;
                String errMsg = "[导入结果] 成功数：" + successCount + ",  失败数：" + failedCount +
                        ",  失败的用户名：" + failedUserNameSet;
                throw new StatusFailException(errMsg);
            }
        }else {
            throw new StatusFailException("当前CSV文件为空，无法插入");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<Object, Object> generateUser(Map<String, Object> params) throws StatusFailException {

        String prefix = (String) params.getOrDefault("prefix", "");
        String suffix = (String) params.getOrDefault("suffix", "");
        int numberFrom = (int) params.getOrDefault("number_from", 1);
        int numberTo = (int) params.getOrDefault("number_to", 10);
        int passwordLength = (int) params.getOrDefault("password_length", 6);

        List<UserInfo> userInfoList = new LinkedList<>();
        List<UserRole> userRoleList = new LinkedList<>();
        List<UserRecord> userRecordList = new LinkedList<>();

        // 暂存用户名和密码
        Map<String, Object> userInfo = new HashMap<>();

        for (int num=numberFrom;num<=numberTo;num++){
            String uuid = IdUtil.simpleUUID();
            String password = "HC@"+RandomUtil.randomString(passwordLength);
            String username = prefix + num + suffix;

            userInfoList.add(new UserInfo()
                    .setUuid(uuid)
                    .setUsername(username)
                    .setPassword(SecureUtil.md5(password)));
            userRoleList.add(new UserRole()
                    .setRoleId(1002L)
                    .setUid(uuid));
            userRecordList.add(new UserRecord().setUid(uuid));

            userInfo.put(username,password);
        }

        boolean a = userInfoEntityService.saveBatch(userInfoList);
        boolean b = userRoleEntityService.saveBatch(userRoleList);
        boolean c = userRecordEntityService.saveBatch(userRecordList);

        if (a&&b&&c){
            String key = IdUtil.simpleUUID();
            redisUtils.hmset(key,userInfo,3600) ;//半小时

            List<String> uidList = userInfoList.stream().map(UserInfo::getUuid).collect(Collectors.toList());
            adminNoticeManager.syncNoticeToNewRegisterBatchUser(uidList);
            return MapUtil.builder().put("key",key).map();
        }else {
            throw new StatusFailException("生成指定用户失败！注意查看组合生成的用户名是否已存在！");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public String addNewUser(List<String> user) throws StatusFailException {

        String uuid = IdUtil.simpleUUID();
        // “用户名”，“密码”，【“邮箱”，"真实姓名"，“性别”，“昵称”，“学校”】
        UserInfo userInfo=new UserInfo()
                .setUuid(uuid)
                .setUsername(user.get(0))
                .setPassword(SecureUtil.md5(user.get(1)))
                .setEmail(user.size() <= 2 || StringUtils.isEmpty(user.get(2)) ? null : user.get(2));
        if (user.size()>=4){
            String realName = user.get(3);
            if (!StringUtils.isEmpty(realName)){
                userInfo.setRealname(realName);
            }
        }
        if (user.size() >= 5) {
            String gender = user.get(4);
            if ("male".equals(gender.toLowerCase()) || "0".equals(gender)) {
                userInfo.setGender("male");
            } else if ("female".equals(gender.toLowerCase()) || "1".equals(gender)) {
                userInfo.setGender("female");
            }
        }
        if (user.size() >= 6) {
            String nickname = user.get(5);
            if (!StringUtils.isEmpty(nickname)) {
                userInfo.setNickname(nickname);
            }
        }
        if (user.size() >= 7) {
            String school = user.get(6);
            if (!StringUtils.isEmpty(school)) {
                userInfo.setSchool(school);
            }
        }
        boolean isOk = userInfoEntityService.save(userInfo);
        UserRole userRole = new UserRole()
                .setRoleId(1002L)
                .setUid(uuid);
        boolean isSave = userRoleEntityService.save(userRole);

        UserRecord userRecord = new UserRecord().setUid(uuid);
        boolean save2 = userRecordEntityService.save(userRecord);
        if (!isOk||!isSave||!save2){
            throw new StatusFailException("用户导入失败");
        }
        return uuid;
    }
}
